package com.doraro.platform.module.user.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.doraro.platform.common.exception.ApiGlobalException;
import com.doraro.platform.common.utils.Constant;
import com.doraro.platform.common.utils.ShiroUserUtil;
import com.doraro.platform.module.user.enums.SysMenuType;
import com.doraro.platform.module.user.mapper.SysMenuMapper;
import com.doraro.platform.module.user.model.entity.SysMenu;
import com.doraro.platform.module.user.model.entity.SysRole;
import com.doraro.platform.module.user.service.ISysMenuService;
import com.google.common.collect.Lists;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

import static com.doraro.platform.module.user.enums.SysMenuType.DIR;
import static com.doraro.platform.module.user.enums.SysMenuType.MENU;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author doraro
 * @since 2019-05-22
 */
@Service
public class SysMenuServiceImpl extends ServiceImpl<SysMenuMapper, SysMenu> implements ISysMenuService {

    @Override
    public List<SysMenu> getTreeList() {
        final List<SysMenu> list = super.list();
        return toTree(0, list);

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer createOrUpdateMenu(SysMenu sysMenu) {
        if (sysMenu == null) {
            return null;
        }
        checkMenuType(sysMenu);
        super.saveOrUpdate(sysMenu);
        ShiroUserUtil.cleanCache();
        return sysMenu.getMenuId();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void removeMenu(Integer menuId) {
        final SysMenu menu = getById(menuId);
        if (menu == null) {
            throw new ApiGlobalException("菜单不存在!");
        }
        final Integer count = lambdaQuery().eq(SysMenu::getParentId, menuId).count();
        if (count > 0) {
            throw new ApiGlobalException("请先删除子菜单");
        }
        super.removeById(menuId);
        ShiroUserUtil.cleanCache();
    }

    @Override
    public List<SysMenu> getTreeList(List<SysRole> roles) {
        if (roles == null) {
            return Lists.newArrayList();
        }
        List<Integer> roleIds = new ArrayList<>(roles.size());
        for (SysRole role : roles) {
            if (Constant.ADMIN_NAME.equals(role.getName())) {
                return this.getTreeList();
            }
            roleIds.add(role.getId());
        }
        List<SysMenu> list = baseMapper.getMenuByRoleIds(roleIds);
        return toTree(0, list);
    }

    /**
     * 目录->导航菜单->功能按钮
     * 根目录或者根页面parentId = 0
     *
     * @param sysMenu
     */
    private void checkMenuType(SysMenu sysMenu) {
        final SysMenuType menuType = sysMenu.getMenuType();
        final Integer parentId = sysMenu.getParentId();
        if (parentId.equals(0)) {
            if (!(menuType.equals(DIR) || menuType.equals(SysMenuType.MENU))) {
                throw new ApiGlobalException("菜单类型错误");
            }
            return;
        }
        final SysMenu parent = super.getById(parentId);
        if (parent == null) {
            throw new ApiGlobalException("不存在该父菜单");
        }
        final SysMenuType parentMenuType = parent.getMenuType();

        if (parentMenuType.equals(SysMenuType.BUTTON)) {
            throw new ApiGlobalException("父菜单类型不允许为功能按钮");
        }
        final String message = "菜单类型错误,当前类型为:" + menuType.getType() + ",父类类型为:" + parentMenuType.getType();
        switch (menuType) {
            case DIR:
                if (!parentId.equals(0)) {
                    throw new ApiGlobalException(message);
                }
                break;
            case MENU:
                if (!parentMenuType.equals(DIR)) {
                    throw new ApiGlobalException(message);
                }
                break;
            case BUTTON:
                if (!parentMenuType.equals(MENU)) {
                    throw new ApiGlobalException(message);
                }
                break;
            default:
                break;
        }

    }


    private List<SysMenu> toTree(Integer parentId, List<SysMenu> list) {
        Objects.requireNonNull(list);
        if (list.isEmpty()) {
            return Lists.newArrayList();
        }
        final List<SysMenu> root = list.stream()
                .filter(sysMenu -> sysMenu.getParentId().equals(parentId))
                .sorted(Comparator.comparingInt(SysMenu::getOrderNum).reversed())
                .collect(Collectors.toList());
        list.removeAll(root);
        for (SysMenu sysMenu : root) {
            sysMenu.setChildren(toTree(sysMenu.getMenuId(), list));
        }
        return root;
    }
}
